// Package common
// @Author: Zhenwei Xiao
// @Description:
// @Version: 1.0.0
// @Date: 2021/4/20 3:46 下午
// @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
//

const fs = require('fs')
var logger = require('tracer')
const home = require("./HomePath")
const path = require("path")
const moment = require('moment')

var _reportCaller = false


//
// 根据字符串返回日志等级枚举值
//
// @Description:
//	返回值 >= 0  => 表示对应的日志等级
//	返回值 = -1  => 表示不输出日志
// @param logLevel string
// @return logrus.Level
//
function getLogLevelByString(logLevel) {
    switch (logLevel) {
        case "NONE":
            return 6
        case "ERROR":
            return 5
        case "WARN":
            return 4
        case "INFO":
            return 3
        case "DEBUG":
            return 2
        case "TRACE":
            return 1
        case "ALL":
            return 0
    }
    return 3
}

//
// 根据字符串获取日志的输出格式
//
// @Description:
// @param logFormat  string
// @return logrus.Formatter
//
function getLogFormatByString(logFormat) {
    switch (logFormat) {
        case "json":
            return JSONFormatter
        case "text":
        default:
            return TextFormatter
    }
    return TextFormatter
}

//
// 确保某个指定的文件夹存在，存在则直接返回，不存在则创建
//
// @Description:
// @param dirPath		/var/log/mir
// @return error
//
function ensureDirExists(dirPath) {
    var isExits
    try{
        if (fs.existsSync(dirPath)) {
            let tempstats = fs.statSync(dirPath);
            if (tempstats.isDirectory()||tempstats.isFile()) {
                isExits = [true, null]

            }
        }
        else{
            isExits = [false, null]
        }
    }catch(err){
        isExits = [false, err]
    }

    if (isExits[1] != null) {
        throw new Error("The file can't be created!!!");
    }
    if (!isExits[0]) {
        try{
            fs.mkdirSync(dirPath, { recursive: true })
        }catch(err){
            throw new Error("The file can't be created!!!")
        }
    }
}

class LoggerParameters {
    constructor() {
        this.ReportCaller = true
        this.LogLevel     = ""
        this.LogFormat    = ""
        this.LogFilePath  = ""
    }
    // ReportCaller bool
    // LogLevel     string
    // LogFormat    string
    // LogFilePath  string
}

//
// 日志模块初始化
//
// @Description:
// @param loggerParameters *LoggerParameters
//
function InitLogger(loggerParameters) {
    _reportCaller = loggerParameters.ReportCaller
    // _logger.SetReportCaller(false)                                         // 日志输出时添加文件名和函数名
    logger.console({level: getLogLevelByString(loggerParameters.LogLevel)})       // 设置日志等级
    // logger.SetFormatter(getLogFormatByString(loggerParameters.LogFormat)) // 设置日志输出格式

    // 处理指定的文件夹路劲是用户目录开头的情况，例如：~/.mir
    if (loggerParameters.LogFilePath.startsWith("~")) {
        var homePath = home.Home()
        if (homePath != null) {
            logger.console().fatal("Get current user home path failed!")
        }
        loggerParameters.LogFilePath = homePath[0] + loggerParameters.LogFilePath.substring(1,loggerParameters.LogFilePath.length)
    }

    // 设置日志的输出目标
    if (loggerParameters.LogFilePath == "") {
        // 如果为指定路径，则输出到控制台
        logger = logger.console()
    } else {
        // 确保文件夹存在
        try{
            ensureDirExists(loggerParameters.LogFilePath)
        } catch (err){
            LogFatal(err.Error())
        }

        // 根据当前时间戳创建一个本次启动的日志输出
        let currentTime =  moment(Date.now()).format('YYYY-MM-DD HH:mm:ss')
        var logFilePath = loggerParameters.LogFilePath + path.sep + currentTime + ".log"
        LogInfo(logFilePath)
        try{
            fs.mkdirSync(logFilePath, { recursive: true })
        }catch(err){
            logger.console().fatal(err.Error())
        }
        //var logger = require('tracer').console()
        logger.console({
            transport: function(data) {
                console.log(data.output)
                fs.appendFile(logFilePath, data.rawoutput + '\n', err => {
                    if (err) throw err
                })
            }
        })
    }
}

//
// 日志模块初始化
//
// @Description:
// @return *logrus.Entry
//
function prepareLogger() {
    // 替换内置stackTraceLimit、prepareStackTrace
    const limit = Error.stackTraceLimit;
    Error.stackTraceLimit = 2; // 只捕捉前2层堆栈

    // 捕捉放入空对象
    let obj = Object.create(null);
    Error.captureStackTrace(obj);
    let line = obj.stack.getLineNumber(); // 获得自定义堆栈
    let file = obj.stack.getFileName();
    // 还原内置stackTraceLimit、prepareStackTrace
    Error.stackTraceLimit = limit;

    if (_reportCaller) {
        return {
            format: [
                '{{file}}:{{line}}', //default format
            ],
        }
    }
    else {
        return {
            format: [
                '{{timestamp}} <{{title}}> {{message}} (in {{file}}:{{line}})', //default format
            ]
        }
    }
}

// LogLevel: Trace < Debug < Info < Warn < Error < Fatal < Panic

function LogTrace(args) {
    logger.colorConsole(prepareLogger()).trace(args)
}

function LogTraceWithFields(fields, args) {
    logger.colorConsole(fields).trace(args)
}

function LogDebug(args) {
    logger.colorConsole(prepareLogger()).debug(args)
}

function LogDebugWithFields(fields, args) {
    logger.colorConsole(fields).debug(args)
}

function LogInfo(args) {
    logger.colorConsole(prepareLogger()).info(args)
}

function LogInfoWithFields(fields, args) {
    logger.colorConsole(fields).info(args)
}

function LogWarn(args) {
    logger.colorConsole(prepareLogger()).warn(args)
}

function LogWarnWithFields(fields, args) {
    logger.colorConsole(fields).warn(args)
}

function LogError(args) {
    logger.colorConsole(prepareLogger()).error(args)
}

function LogErrorWithFields(fields, args) {
    logger.colorConsole(fields).error(args)
}

function LogFatal(args) {
    logger.colorConsole(prepareLogger()).fatal(args)
}

function LogFatalWithFields(fields, args) {
    logger.colorConsole(fields).fatal(args)
}

// To Do
// function LogPanic(args) {
//     logger.colorConsole(prepareLogger()).panic(args)
// }
//
// function LogPanicWithFields(fields, args) {
//     logger.colorConsole(fields).panic(args)
// }



/////////////////////////////////////////////////////////////////////////////////////////////////////////
///// 错误处理
/////////////////////////////////////////////////////////////////////////////////////////////////////////

class LoggerError extends Error{
    constructor(m) {
        super(m)
        this.name = "LoggerError"
    }

    error() {
        console.log(`${this.name}: ${this.message}`)
    }
}

module.exports = {
    getLogLevelByString: getLogLevelByString,
    getLogFormatByString: getLogFormatByString,
    LoggerParameters: LoggerParameters,
    InitLogger: InitLogger,
    LogTrace: LogTrace,
    LogTraceWithFields: LogTraceWithFields,
    LogDebug: LogDebug,
    LogDebugWithFields: LogDebugWithFields,
    LogInfo: LogInfo,
    LogInfoWithFields: LogInfoWithFields,
    LogWarn: LogWarn,
    LogWarnWithFields: LogWarnWithFields,
    LogError: LogError,
    LogErrorWithFields: LogErrorWithFields,
    LogFatal: LogFatal,
    LogFatalWithFields: LogFatalWithFields
}

